import type { ComponentStyleIdType, PlatformTypeValue } from '../../../types/interfaces'
import type { SearchBaseSelectors } from '../appearance/style_enhancement/platforms'
import $ from 'jquery'
import { BaseModule } from '../../../lib/abstract'
import { PageHandler } from '../../../lib/page_handler'
import {
  BING_SEARCH_PAGE_SELECTORS,
  BingPageType,
} from '../../../lib/page_handler/platform/bing/types'
import {
  GOOGLE_SEARCH_PAGE_SELECTORS,
  GooglePageType,
} from '../../../lib/page_handler/platform/google/types'
import {
  SO_SEARCH_BOX_SELECTOR,
  SO_SEARCH_PAGE_SELECTORS,
  SoPageType,
} from '../../../lib/page_handler/platform/so/types'
import {
  SOGOU_SEARCH_PAGE_SELECTORS,
  SogouPageType,
} from '../../../lib/page_handler/platform/sogou/types'
import { ToolKit } from '../../../lib/utils/toolkit'
import {
  BodyAttrs,
  ComponentStyleId,
  HOSTNAME,
  logger,
  SUPPORTED_PLATFORMS,
} from '../../../types/constants'
import { ConfigManager } from '../../config_manager'

interface CleanConfig {
  config: SearchBaseSelectors
  delay?: number
  prepare?: () => void
  action: (config: SearchBaseSelectors) => void
}
type PageCleanConfig = Record<string, CleanConfig>
type PlatformCleanConfig = Partial<Record<PlatformTypeValue, PageCleanConfig>>

interface Config {
  enabled?: boolean
}

export class CleanSearchHistory extends BaseModule {
  readonly id: string = 'clean_search_history'
  readonly styleId: string = ComponentStyleId[this.name]
  isInitialized: boolean = false
  readonly supportedPlatforms: string[] = ConfigManager.getInstance().moduleSupportedPlatforms(this.name)
  private static instance: CleanSearchHistory
  private readonly defaultDelay: number = 300

  config: Config = {
    enabled: true,
  }

  get name(): ComponentStyleIdType {
    return 'CleanSearchHistory'
  }

  get pageType(): SogouPageType {
    return PageHandler.getCurrentPageType() as SogouPageType
  }

  /**
   * 获取单例实例
   */
  public static getInstance(): CleanSearchHistory {
    if (!CleanSearchHistory.instance) {
      CleanSearchHistory.instance = new CleanSearchHistory()
    }
    return CleanSearchHistory.instance
  }

  core(): void {
    this.loadConfig()

    if (!this.config.enabled)
      return

    this.applyClean()
  }

  onToggleCallback(_id: string, checked: boolean): void {
    super.onToggleCallback(_id, checked)
  }

  applyClean(): void {
    const AllConfig: PlatformCleanConfig = {
      [SUPPORTED_PLATFORMS.GOOGLE]: {
        [GooglePageType.Index]: {
          config: GOOGLE_SEARCH_PAGE_SELECTORS[GooglePageType.Index]!,
          delay: 300,
          prepare: () => this.activateSearchInput(GOOGLE_SEARCH_PAGE_SELECTORS[GooglePageType.Index]!.searchBox.input),
          action: config => this.clickItemDeleteButton(config),
        },
        [GooglePageType.IndexHk]: {
          config: GOOGLE_SEARCH_PAGE_SELECTORS[GooglePageType.IndexHk]!,
          delay: 300,
          prepare: () => this.activateSearchInput(GOOGLE_SEARCH_PAGE_SELECTORS[GooglePageType.IndexHk]!.searchBox.input),
          action: config => this.clickItemDeleteButton(config),
        },
        [GooglePageType.All]: {
          config: GOOGLE_SEARCH_PAGE_SELECTORS[GooglePageType.All]!,
          delay: 300,
          prepare: () => this.activateSearchInput(GOOGLE_SEARCH_PAGE_SELECTORS[GooglePageType.All]!.searchBox.input),
          action: config => this.clickItemDeleteButton(config),
        },
        [GooglePageType.Video]: {
          config: GOOGLE_SEARCH_PAGE_SELECTORS[GooglePageType.Video]!,
          delay: 300,
          prepare: () => this.activateSearchInput(GOOGLE_SEARCH_PAGE_SELECTORS[GooglePageType.Video]!.searchBox.input),
          action: config => this.clickItemDeleteButton(config),
        },
        [GooglePageType.ShortVideo]: {
          config: GOOGLE_SEARCH_PAGE_SELECTORS[GooglePageType.ShortVideo]!,
          delay: 300,
          prepare: () => this.activateSearchInput(GOOGLE_SEARCH_PAGE_SELECTORS[GooglePageType.ShortVideo]!.searchBox.input),
          action: config => this.clickItemDeleteButton(config),
        },
        [GooglePageType.Web]: {
          config: GOOGLE_SEARCH_PAGE_SELECTORS[GooglePageType.Web]!,
          delay: 300,
          prepare: () => this.activateSearchInput(GOOGLE_SEARCH_PAGE_SELECTORS[GooglePageType.Web]!.searchBox.input),
          action: config => this.clickItemDeleteButton(config),
        },
      },
      [SUPPORTED_PLATFORMS.BING]: {
        [BingPageType.Web]: {
          config: BING_SEARCH_PAGE_SELECTORS[BingPageType.Web]!,
          delay: 300,
          prepare: () => this.activateSearchInput(BING_SEARCH_PAGE_SELECTORS[BingPageType.Web]!.searchBox.input),
          action: config => this.clickItemDeleteButton(config),
        },
        [BingPageType.Video]: {
          config: BING_SEARCH_PAGE_SELECTORS[BingPageType.Video]!,
          delay: 300,
          prepare: () => this.activateSearchInput(BING_SEARCH_PAGE_SELECTORS[BingPageType.Video]!.searchBox.input),
          action: config => this.clickItemDeleteButton(config),
        },
        [BingPageType.Academic]: {
          config: BING_SEARCH_PAGE_SELECTORS[BingPageType.Academic]!,
          delay: 300,
          prepare: () => this.activateSearchInput(BING_SEARCH_PAGE_SELECTORS[BingPageType.Academic]!.searchBox.input),
          action: config => this.clickItemDeleteButton(config),
        },
        [BingPageType.Dictionary]: {
          config: BING_SEARCH_PAGE_SELECTORS[BingPageType.Dictionary]!,
          delay: 300,
          prepare: () => this.activateSearchInput(BING_SEARCH_PAGE_SELECTORS[BingPageType.Dictionary]!.searchBox.input),
          action: config => this.clickItemDeleteButton(config),
        },
        [BingPageType.Index]: {
          config: BING_SEARCH_PAGE_SELECTORS[BingPageType.Index]!,
          delay: 300,
          prepare: () => this.activateSearchInput(BING_SEARCH_PAGE_SELECTORS[BingPageType.Index]!.searchBox.input),
          action: config => this.clickItemDeleteButton(config),
        },
      },
      // TODO: 不支持微信、微信主页，因为需要悬浮历史记录才会显示删除按钮
      [SUPPORTED_PLATFORMS.SO_GOU]: {
        [SogouPageType.Web]: this.getSogouConfig(SogouPageType.Web),
        [SogouPageType.Zhihu]: this.getSogouConfig(SogouPageType.Zhihu),
        [SogouPageType.Medical]: this.getSogouConfig(SogouPageType.Medical),
        [SogouPageType.Ask]: this.getSogouConfig(SogouPageType.Ask),
        [SogouPageType.Encyclopedia]: this.getSogouConfig(SogouPageType.Encyclopedia),
        [SogouPageType.News]: this.getSogouConfig(SogouPageType.News),
        [SogouPageType.Knowledge]: this.getSogouConfig(SogouPageType.Knowledge),
        [SogouPageType.IndexSearch]: this.getSogouConfig(SogouPageType.IndexSearch),
      },
      [SUPPORTED_PLATFORMS.SO]: {
        // 网页会在搜索关键词恢复后，弹出搜索建议，影响用户体验，所以这里不启用
        // [SoPageType.Web]: this.getSoConfig(SoPageType.Web),
        [SoPageType.Video]: this.getSoConfig(SoPageType.Video),
        [SoPageType.News]: this.getSoConfig(SoPageType.News),
        [SoPageType.Wenku]: this.getSoConfig(SoPageType.Wenku),
        [SoPageType.IndexSearch]: this.getSoConfig(SoPageType.IndexSearch),
        [SoPageType.IndexVideo]: this.getSoConfig(SoPageType.IndexVideo),
        [SoPageType.IndexWenku]: this.getSoConfig(SoPageType.IndexWenku),
      },
    }

    const platformConfig = AllConfig[HOSTNAME]

    if (!platformConfig)
      return

    const pageConfig = platformConfig[this.pageType]

    if (!pageConfig)
      return

    const { config, delay = this.defaultDelay, prepare, action } = pageConfig

    if (prepare)
      prepare()

    setTimeout(() => {
      action(config)
    }, delay)
  }

  /**
   * 获取搜狗搜索页面的清理配置
   */
  getSogouConfig(pageType: SogouPageType): CleanConfig {
    const config = SOGOU_SEARCH_PAGE_SELECTORS[pageType]!

    return {
      config,
      delay: 0,
      prepare: () => {
        this.refreshSearchInput({
          inputSelector: config.searchBox.input,
          historyContainer: config.searchBox.dropdown.history,
          delay: 300,
        })
      },
      action: config => this.clickDeleteButton(
        config,
        {
          // 【搜狗搜索】【搜索主页】没有历史记录本身就没不会有删除按钮，所以不需要打印警告日志
          printWaringLog: pageType !== SogouPageType.IndexSearch,
        },
      ),
    }
  }

  /**
   * 获取 360 搜索页面的清理配置
   */
  getSoConfig(pageType: SoPageType): CleanConfig {
    const config = SO_SEARCH_PAGE_SELECTORS[pageType]!

    const defaultPageCleanConfig: CleanConfig = {
      config,
      delay: 100,
      prepare: () => { },
      action: config => this.clickDeleteButton(config),
    }

    const pageCleanConfig: Partial<Record<SoPageType, CleanConfig>> = {
      // TODO: 【视频】试了多种方法去触发输入框事件，还是找不到删除历史按钮
      [SoPageType.Web]: {
        ...defaultPageCleanConfig,
        prepare: () => {
          this.refreshSearchInput({
            inputSelector: config.searchBox.input,
            historyContainer: SO_SEARCH_BOX_SELECTOR,
            delay: 300,
            beforeHidingHistory: () => {
              const $inputBox = $(SO_SEARCH_BOX_SELECTOR).siblings('#suggest-align')
              const inputBoxBorderRadius = $inputBox.css('border-radius')
              $inputBox[0]?.style.setProperty('border-radius', inputBoxBorderRadius, 'important')
            },
            afterRefresh: () => {
              $(SO_SEARCH_BOX_SELECTOR).siblings('#suggest-align').css('border-radius', '')
            },
          })
        },
      },
    }

    return pageCleanConfig[pageType] || defaultPageCleanConfig
  }

  /**
   * 激活搜索输入框
   */
  private activateSearchInput(inputSelector: string, activationMethod: 'click' | 'focus' = 'click'): void {
    const $searchInput = $(inputSelector)

    if (!$searchInput || $searchInput.length === 0)
      logger.warn(`${this.name} 未找到搜索输入框: ${inputSelector}`)

    $searchInput.trigger(activationMethod)
    logger.info(`[${this.name}] 已激活输入框: ${inputSelector}`)
  }

  /**
   * 刷新搜索输入状态
   */
  private refreshSearchInput(options: {
    inputSelector: string
    historyContainer: string
    delay?: number
    beforeHidingHistory?: () => void
    afterRefresh?: () => void
  }): void {
    const {
      inputSelector,
      historyContainer,
      delay = this.defaultDelay,
      beforeHidingHistory,
      afterRefresh,
    } = options
    const $searchInput = $(inputSelector)
    const $historyContainer = $(historyContainer)

    if (!$searchInput || $searchInput.length === 0)
      logger.warn(`[${this.name}] 未找到搜索输入框: ${inputSelector}`)

    if (!$historyContainer || $historyContainer.length === 0)
      logger.warn(`[${this.name}] 未找到搜索历史容器: ${historyContainer}`)

    const originalKeyword = $searchInput.val()?.toString() || ''
    const isHistoryHidden = ($historyContainer.attr(BodyAttrs.HIDE_TYPE) || '') !== ''

    // 1. 先执行自定义操作
    if (beforeHidingHistory)
      beforeHidingHistory()

    // 2. 隐藏搜索历史
    if (!isHistoryHidden)
      ToolKit.dom.showControl($historyContainer, { show: false, softHide: true })

    // 3. 清空搜索框并触发激活事件
    $searchInput.val('').trigger('focus').trigger('click')

    // 4. 重新输入原始关键词
    setTimeout(() => {
      // 5. 恢复搜索关键词，且搜索框失去焦点
      $searchInput.val(originalKeyword).trigger('blur')

      // 6. 恢复历史显示状态
      if (!isHistoryHidden) {
        if (afterRefresh)
          afterRefresh()

        ToolKit.dom.showControl($historyContainer, { show: true, softShow: true })
      }
    }, delay)
  }

  /**
   * 【删除方式一】点击历史记录删除按钮
   */
  private clickItemDeleteButton(config: SearchBaseSelectors): void {
    const $elements = $(config.searchBox.dropdown.clearHistoryBtn)

    if (!$elements || $elements.length === 0) {
      logger.warn(`[${this.name}] 未找到搜索历史记录删除按钮`)
      return
    }

    $elements.each((_, element) => {
      element.click()
    })
    logger.attention(`[${this.name}] 已清除 ${$elements.length} 条历史记录`)
  }

  /**
   * 【删除方式二】点击全部删除按钮
   */
  private clickDeleteButton(config: SearchBaseSelectors, options?: {
    printWaringLog?: boolean
    click?: ($elements: JQuery<HTMLElement>) => void
  }): void {
    const $elements = $(config.searchBox.dropdown.clearHistoryBtn)
    const buttonTexts = config.searchBox.dropdown.clearHistoryText

    const {
      printWaringLog = true,
      click = ($el: JQuery<HTMLElement>) => {
        $el.each((_, element) => {
          element.click()
        })
      },
    } = options || {}

    if (!$elements || $elements.length === 0) {
      if (printWaringLog) {
        logger.warn(`[${this.name}] 未找到'${buttonTexts}'按钮`)
      }
      return
    }
    else if ($elements.length > 1) {
      logger.warn(`[${this.name}] 找到多个'${buttonTexts}'按钮`)
      return
    }

    // 点击删除按钮
    click($elements)

    logger.attention(`[${this.name}] 已清除历史记录`)
  }

  applyConfig(config: Partial<Config>): void {
    super.updateConfig(config)

    this.applyClean()

    logger.info(`[${this.name}] Config updated and apply`, this.config)
  }

  getStyles(): string {
    return ``
  }
}
